#pragma once

#include <iostream>
#include <vector>
#include <queue>
#include <pthread.h>
#include "LockGuard.hpp"
#include "Thread.hpp"
#include "Log.hpp"

using namespace ThreadModule;

const static int MAX_THREAD_NUM = 5;

// 日志
template <typename T>
class ThreadPool
{
private:
    
    //封装一下source_queue的锁
    void LockQueue()
    {
        LockGuard lock(&_mutex);
    }
    void UnlockQueue()
    {
        pthread_mutex_unlock(&_mutex);
    }
    void ThreadSleep()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }

    void ThraedWakeUp()
    {
        pthread_cond_signal(&_cond);
    }
     void ThreadWakeUpAll()
    {
        pthread_cond_broadcast(&_cond);
    }


    // 禁用拷贝复制
    ThreadPool<T> &operator=(const ThreadPool<T> &) = delete;
    ThreadPool(const ThreadPool<T> &) = delete;

    // 要有构造函数，但是必须是私有
    ThreadPool(int thread_num = MAX_THREAD_NUM)
        : _thread_num(thread_num), _wait_num(0), _isrunning(false)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
        LOG(INFO, "ThreadPool Constructor()");
    }


    void InitThreadPool()
    {
        for (size_t i = 0; i < _thread_num; i++)
        {
            std::string name="Thread-"+std::to_string(i+1);
            //std::placeholders::_1是一个占位符，表示在调用 ThreadFunc 时传递的第一个参数。这使得 ThreadFunc 可以接受外部传入的参数。
            _threads.emplace_back(std::bind(&ThreadPool::ThreadFunc, this,std::placeholders::_1),name);
            LOG(INFO, "init thread: %s done",name.c_str());
        }

        _isrunning= true;
        
    }

    void Start()
    {
        for (auto &thread : _threads)
        {
            thread.Start();
        }
    }

void ThreadFunc(std::string name)
{
    LOG(INFO, "%s is running...",name.c_str());

    while(true)
    {
        //保证队列安全
        LockQueue();
        //队列没有数据或者线程池没有运行
        while (_task_queue.empty() && _isrunning)
        {
            _wait_num++;
            ThreadSleep();
            //如果从休眠中出来，等待数量要减少
            _wait_num--;
        }
        //1 线程池已经退出了 && 任务队列是空的
        //可以解锁跳出循环了
        if (_task_queue.empty()&&!_isrunning)
        {
            UnlockQueue();
            break;
        }
        //2 线程池不退出&&任务队列不是空的
        //3 线程池退出了&&任务队列不是空的 ----处理完所有任务才能退出
        //3 有任务就会一定在处理任务

        T t=_task_queue.front();
        _task_queue.pop();
        UnlockQueue();
        LOG(DEBUG,"%s get a task",name.c_str());
        
        //处理任务
        t();
       // LOG(DEBUG,"%s task done,result is: %s",name.c_str(),t.ResultToString().c_str());

    }
}



public:
   //获取单例对象
    static ThreadPool<T> *GetInstance()
    {
            //双检查
        if(_instance==nullptr)
        {
            LockGuard lock(&_lock);
            if(_instance==nullptr)
            {
                _instance=new ThreadPool<T>();
                _instance->InitThreadPool();
                _instance->Start();
                LOG(INFO, "Create a thread pool singleton");
                return _instance;
            }
        }  

        LOG(INFO, "Obtain the thread pool singleton");  
         return _instance;
    }

   void Stop()
   {
    LockGuard();
    _isrunning=false;
    ThreadWakeUpAll();
    UnlockQueue();
   }

   void Wait()
   {
    for (auto &thread : _threads)
    {
        thread.Join();
        LOG(INFO, "thread %s is exit",thread.GetName().c_str());
    }
   }
   
/**
 * @brief 向队列中添加任务项
 * 
 * 本函数尝试将一个任务项添加到任务队列中。首先锁定队列以确保线程安全，
 * 然后检查当前是否正在运行。如果正在运行，则将任务项添加到队列中并返回true。
 * 如果有线程正在等待任务，则唤醒一个线程。如果添加任务时队列没有运行，
 * 则解锁队列并返回false。
 * 
 * @param t 要添加到队列的任务项
 * @return true 如果任务项成功添加到队列中，否则返回false
 */
bool Enqueue(const T& t)
{ 
    bool ret=false;
    // 锁定队列以确保线程安全
    LockQueue();
    // 检查当前是否正在运行
    if(_isrunning)
    {
        // 将任务项添加到队列中
        _task_queue.push(t);
        ret=true;
        // 如果有线程正在等待任务，则唤醒一个线程
        if(_wait_num>0)
        {
            ThraedWakeUp();
        }
        // 记录日志信息，表示任务已成功添加到队列
        LOG(DEBUG, "push a task to queue");
        ret = true;
    }
    // 解锁队列
    UnlockQueue();
    // 根据任务是否成功添加到队列中返回true或false
    return ret;
}

   ~ThreadPool()
   {
       pthread_mutex_destroy(&_mutex);
       pthread_cond_destroy(&_cond);
   }

private:
    int _thread_num;
    std::vector<Thread> _threads;
    std::queue<T> _task_queue;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond; // 条件变量

    int _wait_num;
    bool _isrunning;

    // 添加单例模式
    static ThreadPool<T> *_instance;
    static pthread_mutex_t _lock;
};

//静态成员在类外初始化
template <typename T>
ThreadPool<T> *ThreadPool<T>::_instance = nullptr;

template <typename T>
pthread_mutex_t ThreadPool<T>::_lock = PTHREAD_MUTEX_INITIALIZER;
